Skip to content

Speed-independent scope trail persistence (XY plots)#240

Open
esaruoho wants to merge 1 commit intopfalstad:devfrom
esaruoho:v3-mosfet-and-scope-fixes
Open

Speed-independent scope trail persistence (XY plots)#240
esaruoho wants to merge 1 commit intopfalstad:devfrom
esaruoho:v3-mosfet-and-scope-fixes

Conversation

@esaruoho
Copy link
Copy Markdown

@esaruoho esaruoho commented Mar 2, 2026

Summary

Addresses all of @pfalstad's feedback on this PR. MOSFET lambda part removed — superseded by #313 (MosfetModel class). This PR is now scope-fade-only.

Scope trail persistence — three things you asked for

  1. "Vary alpha instead of the number of draw calls" — replaced the alphaCounter > 2 draw-call counter with a real per-frame fade alpha.

  2. "Should look the same regardless of simulation speed setting" — the alpha is computed from elapsed wall-clock time, not frame count, using the analytic exponential-decay formula:

    alpha = 1 - exp(-elapsed_ms / trailPersistence)
    

    Same trail at 30fps or 144fps because elapsed time appears in the exponent, not the multiplier.

  3. "Still too persistent even at the lowest setting" — the user setting is now a literal time constant in milliseconds (default 200 ms, range 0..2000 ms). Setting it to 0 sets alpha = 1 → instant erase → genuinely no trail at all. So "lowest persistence" actually means no trail.

UX

The Scope Properties dialog now shows a single slider labelled "Trail Persistence (ms)" with a numeric readout next to it (200 ms, 500 ms, …, or none at zero). No more opaque alpha number.

Persistence

Saved per-scope as XML attr tp. Omitted when at the default (200) to keep file size small.

Test plan

  • Open an XY scope (e.g. Plot V vs I on a resistor) → trail visible, decays in ~200 ms by default.
  • Slide trail persistence to 0 → no trail at all (each frame fully overwrites).
  • Slide to 2000 ms → long trail, slow fade.
  • Change simulation speed (slow / fast / max) → trail visual decay rate stays the same wall-clock duration.
  • Save circuit, reload → tp round-trips for non-default values; default circuits unchanged.

🤖 Generated with Claude Code

@pfalstad
Copy link
Copy Markdown
Owner

pfalstad commented Mar 7, 2026

It still seems too persistent even at the lowest setting. Maybe you should vary alpha instead of the number of draw calls between fade outs?

It would also be nice if it looks the same regardless of the simulation speed setting (as much as practical).

The MOSFET looks fine but I would call it "Lambda" in the dialog (since "Beta" is there) and use "la" as the xml dump attr. You don't need to add it to the StringTokenizer constructor.

esaruoho added a commit to esaruoho/circuitjs1 that referenced this pull request Mar 7, 2026
…stence

MOSFET lambda:
- Rename dialog label to "Lambda" (matching "Beta" style)
- Change XML dump attribute from "lambda" to "la"
- Remove lambda from StringTokenizer constructor (XML-only)

Scope trail persistence:
- Replace draw-call-counting with alpha-based fade approach
- Vary alpha value (trailAlpha) instead of skipping draw calls
- Normalize by elapsed wall-clock time for speed independence
- Scrollbar controls alpha 0-0.100 (0 = max persistence)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@esaruoho esaruoho force-pushed the v3-mosfet-and-scope-fixes branch from 4c6eaad to 0f6995d Compare March 7, 2026 21:08
esaruoho added a commit to esaruoho/circuitjs1 that referenced this pull request Apr 15, 2026
…nstant model

Replaces the draw-call-counter scope fade with a wall-clock-based
exponential decay. The user setting now means a literal trail
persistence in milliseconds, not an opaque alpha number.

Per @pfalstad on PR pfalstad#240:
- "vary alpha instead of the number of draw calls between fade outs"
- "should look the same regardless of the simulation speed setting"
- "It still seems too persistent even at the lowest setting"

Implementation:

  alpha = 1 - exp(-elapsed_ms / trailPersistence)

This is the analytic solution for an exponential decay with time
constant `trailPersistence`. Same fade rate at 30fps or 144fps,
because elapsed wall-clock time appears in the exponent. The user
sees and sets the time constant directly (default 200 ms).

Range 0..2000 ms. Setting trailPersistence = 0 maps to alpha = 1
(instant erase, no trail at all) so "lowest setting" really is no
trail, addressing the "still too persistent" complaint.

Persisted per-scope as XML attribute "tp"; omitted when at the
default to keep file size small.

The MOSFET lambda part of the original PR pfalstad#240 has been superseded
by PR pfalstad#313 (MosfetModel class), so this PR is now scope-fade-only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@esaruoho esaruoho force-pushed the v3-mosfet-and-scope-fixes branch from 0f6995d to 52c36f7 Compare April 15, 2026 06:19
@esaruoho esaruoho changed the title MOSFET channel-length modulation, scope trail persistence (#155, #157) Speed-independent scope trail persistence (XY plots) Apr 15, 2026
@esaruoho
Copy link
Copy Markdown
Author

@pfalstad — major rework based on your feedback. Three changes:

  1. MOSFET lambda removed — superseded by Add MosfetModel class with lambda (channel-length modulation) #313 (MosfetModel class), so this PR is now scope-fade-only and the title/description are updated.

  2. Alpha varies, not draw-call countalphaCounter > 2 skip-and-flash is gone. Each frame now fades by an alpha computed for that frame.

  3. Speed-independent + lowest setting really is no trail — used the analytic exponential decay:

    alpha = 1 - exp(-elapsed_ms / trailPersistence)
    

    This is what makes it speed-independent: elapsed wall-clock time appears in the exponent, so the same time constant gives the same visual decay rate at any framerate. The user setting is now a literal persistence in milliseconds (default 200 ms, range 0..2000 ms). At 0 the alpha is 1 → instant erase → no trail. The slider readout shows none / 200 ms / etc. instead of a 0..0.1 alpha number.

Force-pushed onto the rebased branch.

@esaruoho esaruoho changed the base branch from v3-dev to dev April 15, 2026 09:49
…nstant model

Replaces the draw-call-counter scope fade with a wall-clock-based
exponential decay. The user setting now means a literal trail
persistence in milliseconds, not an opaque alpha number.

Per @pfalstad on PR pfalstad#240:
- "vary alpha instead of the number of draw calls between fade outs"
- "should look the same regardless of the simulation speed setting"
- "It still seems too persistent even at the lowest setting"

Implementation:

  alpha = 1 - exp(-elapsed_ms / trailPersistence)

This is the analytic solution for an exponential decay with time
constant `trailPersistence`. Same fade rate at 30fps or 144fps,
because elapsed wall-clock time appears in the exponent. The user
sees and sets the time constant directly (default 200 ms).

Range 0..2000 ms. Setting trailPersistence = 0 maps to alpha = 1
(instant erase, no trail at all) so "lowest setting" really is no
trail, addressing the "still too persistent" complaint.

Persisted per-scope as XML attribute "tp"; omitted when at the
default to keep file size small.

The MOSFET lambda part of the original PR pfalstad#240 has been superseded
by PR pfalstad#313 (MosfetModel class), so this PR is now scope-fade-only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@esaruoho esaruoho force-pushed the v3-mosfet-and-scope-fixes branch from 52c36f7 to 8382a64 Compare April 15, 2026 09:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants